package com.winchain.provider.expiration.service.impl;

import com.shell.bee.acct.account.po.AcctBas;
import com.shell.bee.acct.account.po.AcctBkp;
import com.shell.bee.acct.account.util.VirtualAcctUtil;
import com.shell.bee.acct.transaction.po.AcctTxRec;
import com.shell.bee.acct.transaction.service.AcctTxRecService;
import com.shell.bee.acct.transaction.vo.AcctInfo;
import com.shell.bee.base.utils.DateUtil;
import com.shell.bee.base.utils.SpringContextUtil;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.bee.base.utils.SystemUtil.SystemMode;
import com.shell.bee.persistence.annotation.Pagination;
import com.shell.bee.persistence.model.PageLimit;
import com.shell.bee.persistence.service.impl.PersistentServiceImpl;
import com.shell.bee.persistence.transaction.Transaction;
import com.shell.bee.persistence.transaction.TransactionUtil;
import com.shell.constant.rel.AssetCode;
import com.shell.feign.PubParameterFeign;
import com.shell.framework.command.ChainBase;
import com.shell.framework.command.CommandContext;
import com.shell.framework.utils.CommonDataUtil;
import com.shell.framework.utils.MathsUtil;
import com.shell.framework.utils.MessageSender;
import com.shell.framework.utils.SysDateUtil;
import com.shell.governor.modules.message.keyword.ExpDebitFailedKeyWord;
import com.shell.governor.modules.message.keyword.ExpDebitKeyWord;
import com.shell.governor.modules.vo.ParameterVo;
import com.winchain.chainbill.ChainBillUtil;
import com.winchain.chainbill.asset.biz.credit.cmd.BillAssetTranCmd;
import com.winchain.chainbill.basic.cus.po.CusRec;
import com.winchain.chainbill.basic.cus.service.CusRecService;
import com.winchain.chainbill.bill.base.po.CbHldr;
import com.winchain.chainbill.bill.base.po.CbRec;
import com.winchain.chainbill.bill.base.po.CbSnd;
import com.winchain.chainbill.bill.base.service.CbSndService;
import com.winchain.chainbill.risk.utill.RateUtil;
import com.winchain.chainbill.trade.service.BillAcctBlcService;
import com.winchain.chainbill.trade.service.BillAcctService;
import com.winchain.chainbill.trade.service.TradeService;
import com.winchain.provider.expiration.cmd.BillExpDebitCreditTranCmd;
import com.winchain.provider.expiration.dao.CbDebitDao;
import com.winchain.provider.expiration.exception.DebitException;
import com.winchain.provider.expiration.po.CbDebit;
import com.winchain.provider.expiration.po.CbDebitDtl;
import com.winchain.provider.expiration.po.CbDebitIns;
import com.winchain.provider.expiration.service.BillExpHldrService;
import com.winchain.provider.expiration.service.CbCreditService;
import com.winchain.provider.expiration.service.CbDebitDtlService;
import com.winchain.provider.expiration.service.CbDebitInsService;
import com.winchain.provider.expiration.service.CbDebitService;
import com.winchain.provider.expiration.vo.BatchStats;
import com.winchain.provider.expiration.vo.CbDebitQueryVo;
import com.winchain.provider.expiration.vo.CbDebitVo;
import com.winchain.provider.expiration.vo.PaymentStatsQueryVo;
import com.winchain.provider.expiration.vo.PaymentStatsVo;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("cbDebitService")
public class CbDebitServiceImpl extends PersistentServiceImpl<CbDebit> implements CbDebitService {
	@Autowired
	private CbDebitDao cbDebitDao;
	@Autowired
	private CbSndService cbSndService;
	@Autowired
	private BillExpHldrService billExpHldrService;
	@Autowired
	private TradeService tradeService;
	@Autowired
	private CbDebitDtlService cbDebitDtlService;
	@Autowired
	private BillAssetTranCmd billAssetTranCmd;
	@Autowired
	private BillExpDebitCreditTranCmd billExpDebitCreditTranCmd;
	@Autowired
	private CbCreditService cbCreditService;
	@Autowired
	private CbDebitInsService cbDebitInsService;
	@Autowired
	private PubParameterFeign pubParameterFeign;
	@Autowired
	private AcctTxRecService AcctTxRecService;
	@Autowired
	private BillAcctService billAcctService;
	@Autowired
	private BillAcctBlcService billAcctBlcService;
	@Autowired
	private CusRecService cusRecService;

	@Pagination
	public List<CbDebitVo> selectDebitAbnormalList(PageLimit pageLimit, CbDebitQueryVo cbDebitQueryVo) {
		String cusName = cbDebitQueryVo.getCusName();
		if (!StringUtil.emptyAndNull(cusName)) {
			cusName = StringUtil.getParameterLike(cusName);
			cbDebitQueryVo.setCusName(cusName);
		}
		return this.cbDebitDao.selectDebitAbnormalList(cbDebitQueryVo);
	}

	@Pagination
	public List<CbDebitVo> selectDebitList(PageLimit pageLimit, CbDebitQueryVo cbDebitQueryVo) {
		String cusName = cbDebitQueryVo.getCusName();
		if (!StringUtil.emptyAndNull(cusName)) {
			cusName = StringUtil.getParameterLike(cusName);
			cbDebitQueryVo.setCusName(cusName);
		}
		List<CbDebitVo> debitVos = this.cbDebitDao.selectDebitList(cbDebitQueryVo);
		String systemDate = SysDateUtil.getSystemDate();
		ParameterVo parameter;
		if (!SystemUtil.SystemMode.prod.equals(SystemUtil.getSystemMode())) {
			parameter = this.pubParameterFeign.getCommonParameter("SYS_DATE_CONF");
			if ((parameter != null) && (!StringUtil.emptyAndNull(parameter.getParmValue()))) {
				systemDate = parameter.getParmValue();
			}
		}
		for (CbDebitVo debitVo : debitVos) {
			BigDecimal overdueIns = debitVo.getOverdueIns();
			if (overdueIns == null) {
				String insDay = debitVo.getInsDate();
				if (!StringUtil.emptyAndNull(insDay)) {
					int insDays = DateUtil.getDaysBetween(insDay, systemDate) + 1;
					debitVo.setInsDays(insDays);
					overdueIns = MathsUtil.mathInterest(debitVo.getBillAmount(), debitVo.getOverdueRate(), insDays);
				}
			} else {
				String settleDate = debitVo.getSettleDate();
				String insDate = debitVo.getInsDate();
				int insDays = DateUtil.getDaysBetween(insDate, settleDate) + 1;
				debitVo.setInsDays(insDays);
			}
			debitVo.setOverdueIns(overdueIns);
		}
		return debitVos;
	}

	public BatchStats<String> reDebit(String[] debitIds) {
		String grpId = getGrpIdByDebitId(debitIds[0]);
		if ("batch".equals(ChainBillUtil.getExpSettleMode(grpId))) {
			return onlineDebit(debitIds, false);
		}
		return singleDebit(debitIds, false);
	}

	private BatchStats<String> singleDebit(String[] debitIds, final boolean isDisbursement) {
		final BatchStats<String> stats = new BatchStats();
		final List<CbDebit> successDebits = new ArrayList();
		for (final String debitId : debitIds) {
			try {
				TransactionUtil.execute(new Transaction() {
					public void doInTransaction() {
						CbDebit debit = CbDebitServiceImpl.this.selectAndLockByKey(debitId);
						String debitState = debit.getDebitState();
						if ("1".equals(debitState)) {
							CbDebitServiceImpl.this.logger.warn("Debit has processed successfully.");
							stats.addAbnormalMsg("������������������������");
						} else {
							String cashId;
							if (!isDisbursement) {
								cashId = debit.getCusId();
							} else {
								cashId = CbDebitServiceImpl.this.billExpHldrService
										.getFocalCoIdByBillId(debit.getBillId());
							}
							if ((ChainBillUtil.onlinePay()) && (VirtualAcctUtil.onVirtual())
									&& (!CbDebitServiceImpl.this.enoughBalance(debit, null))) {
								CusRec cus = (CusRec) CbDebitServiceImpl.this.cusRecService.selectByKey(cashId);
								String msg = cus.getCusName() + "����[" + debit.getAcctNo() + "]������������";
								CbDebitServiceImpl.this.logger.warn(msg);
								stats.addAbnormalRecord("2");
								stats.addAbnormalMsg(msg);
								return;
							}
							boolean success = CbDebitServiceImpl.this.cbCreditService.batchCreditByDebitId(debitId,
									cashId, false, false);
							if (success) {
								debitState = "1";
								debit.setDebitState(debitState);
								CbDebitServiceImpl.this.updateNotNull(debit);

								successDebits.add(debit);
								stats.addPassedRecord("1");
							}
						}
					}
				}, new int[0]);
			} catch (Exception e) {
				e.printStackTrace();
				this.logger.error(getClass() + "��������", e);
				stats.addAbnormalRecord("2");
				stats.addAbnormalMsg(e.getMessage());
			}
		}
		String txSnHost = resQuota(successDebits);
		if (txSnHost != null) {
			stats.setTxSnHost(txSnHost);
		}
		return stats;
	}

	public BatchStats<String> disburse(String[] debitIds) {
		String grpId = getGrpIdByDebitId(debitIds[0]);
		if ("batch".equals(ChainBillUtil.getExpSettleMode(grpId))) {
			return onlineDebit(debitIds, true);
		}
		return singleDebit(debitIds, true);
	}

	public BatchStats<String> offlineProcess(String[] debitIds) {
		BatchStats<String> stats = new BatchStats();
		for (String debitId : debitIds) {
			try {
				CbDebit debit = selectAndLockByKey(debitId);
				String rateStr = RateUtil.getOverdueRateByBillId(debit.getBillId(), "overdue_rate", "4");
				if (StringUtil.emptyAndNull(rateStr)) {
					stats.addAbnormalMsg("��������������");
				} else {
					String debitState = debit.getDebitState();
					if ("5".equals(debitState)) {
						this.logger.warn("Debit has processed successfully.");
						stats.addAbnormalMsg("������������������������");
					} else {
						debitState = "5";
						debit.setDebitState(debitState);
						updateNotNull(debit);

						stats.addPassedRecord("1");
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				this.logger.error(getClass() + "��������", e);
				stats.addAbnormalRecord("2");
				stats.addAbnormalMsg(e.getMessage());
			}
		}
		return stats;
	}

	private BatchStats<String> onlineDebit(String[] debitIds, final boolean isDisbursement) {
		final BatchStats<String> stats = new BatchStats();
		final List<CbDebit> pmtSuccessDebits = new ArrayList();
		for (final String debitId : debitIds) {
			try {
				TransactionUtil.execute(new Transaction() {
					public void doInTransaction() {
						CbDebit debit = CbDebitServiceImpl.this.selectAndLockByKey(debitId);
						String debitState = debit.getDebitState();
						if ("1".equals(debitState)) {
							CbDebitServiceImpl.this.logger.warn("Debit has processed successfully.");
						} else {
							String remark = "��������";
							List<String> abnormalMsgs;
							if (!isDisbursement) {
								abnormalMsgs = CbDebitServiceImpl.this.pmt(debit, remark);
								debitState = "1";
								debit.setActualAmount(debit.getBillAmount());
							} else {
								remark = "��������";
								CbDebitServiceImpl.this.pmtByFocal(debit);
								abnormalMsgs = new ArrayList();
								debitState = "6";
							}
							if (abnormalMsgs.size() == 0) {
								debit.setActualAmount(debit.getBillAmount());
								debit.setDebitState(debitState);
								debit.setSettleDate(DateUtil.getSystemDate());
								debit.setRemark(remark);
								CbDebitServiceImpl.this.updateNotNull(debit);
								pmtSuccessDebits.add(debit);
								stats.addPassedRecord("1");
							} else {
								stats.addAbnormalRecord("2");
								stats.setAbnormalMsg(abnormalMsgs);
							}
						}
					}
				}, new int[0]);
			} catch (Exception e) {
				e.printStackTrace();
				this.logger.error(getClass() + "��������", e);
				stats.addAbnormalRecord("2");
				stats.addAbnormalMsg(e.getMessage());
			}
		}
		try {
			for (Iterator<CbDebit> iterator = pmtSuccessDebits.iterator(); iterator.hasNext();) {
				CbDebit debit = iterator.next();
				this.cbCreditService.creditByDebitId(debit.getDebitId());
			}
		} catch (Exception e) {
			e.printStackTrace();
			this.logger.error("credit error.", e);
		}
		String txSnHost = resQuota(pmtSuccessDebits);
		if (txSnHost != null) {
			stats.setTxSnHost(txSnHost);
		}
		return stats;
	}

	private boolean pmtByFocal(CbDebit debit) {
		return true;
	}

	public BatchStats<String> confirmDebit(String[] debitIds, final String cashId, final String settleDate,
			final BigDecimal actualAmount, final BigDecimal overdueIns, final String remark) {
		final BatchStats<String> stats = new BatchStats();
		final List<CbDebit> debits = new ArrayList();
		for (final String debitId : debitIds) {
			final String grpId = getGrpIdByDebitId(debitId);
			try {
				TransactionUtil.execute(new Transaction() {
					public void doInTransaction() {
						CbDebit debit = CbDebitServiceImpl.this.selectAndLockByKey(debitId);
						String debitState = debit.getDebitState();
						if ("1".equals(debitState)) {
							CbDebitServiceImpl.this.logger.warn("Debit has processed successfully.");
							stats.addAbnormalMsg("������������������������");
							return;
						}
						boolean success = true;
						if ((ChainBillUtil.onlinePay()) && (VirtualAcctUtil.onVirtual())) {
							AcctBas acct = CbDebitServiceImpl.this.billExpHldrService.getCashAcct(cashId);
							CbDebit tmp = new CbDebit();
							tmp.setAcctNo(acct.getAcctNo());
							tmp.setBillAmount(actualAmount);
							tmp.setBillId(debit.getBillId());
							if (!CbDebitServiceImpl.this.enoughBalance(tmp, null)) {
								String msg = acct.getCustNm() + "����[" + acct.getAcctNo() + "]������������";
								stats.addAbnormalRecord("2");
								stats.addAbnormalMsg(msg);
								return;
							}
						}
						CbDebitIns debitIns = CbDebitServiceImpl.this.cbDebitInsService.selectByDebitId(debitId);
						if (debitIns != null) {
							debitIns.setSettleDate(settleDate);
							debitIns.setOverdueIns(overdueIns);
							debitIns.setOverdueState("1");
							CbDebitServiceImpl.this.cbDebitInsService.updateNotNull(debitIns);
						}
						String txSn;
						if (("batch".equals(ChainBillUtil.getExpSettleMode(grpId)))
								&& (debit.getCusId().equals(cashId))) {
							List<CbDebitDtl> debitDtls = CbDebitServiceImpl.this.cbDebitDtlService
									.selectByDebitId(debit.getDebitId());
							txSn = SystemUtil.getUUID();
							for (CbDebitDtl debitDtl : debitDtls) {
								AcctTxRec tx = CbDebitServiceImpl.this.getAcctTxRec(debit, debitDtl, txSn, cashId);
								tx.setTxAbs("��������");
								Map<String, String> ret = null;
								if (ChainBillUtil.onlinePay()) {
									ret = CbDebitServiceImpl.this.tradeService.fire(tx);
								} else {
									CbDebitServiceImpl.this.tradeService.rollback(tx);
									ret = new HashMap();
									ret.put("ret_code", "S");
								}
								success = "S".equals(ret.get("ret_code"));
							}
						}
						if ("single".equals(ChainBillUtil.getExpSettleMode(grpId))) {
							success = CbDebitServiceImpl.this.cbCreditService.batchCreditByDebitId(debitId, cashId,
									false, true);
						}
						BigDecimal actualOverdueIns = actualAmount.subtract(debit.getBillAmount());
						if ((success) && (actualOverdueIns.compareTo(BigDecimal.ZERO) == 1)) {
							AcctTxRec tx = CbDebitServiceImpl.this.getOverdueInsAcctTxRec(cashId, debit,
									actualOverdueIns);
							tx.setTxAbs("������������");
							Object ret = null;
							if (ChainBillUtil.onlinePay()) {
								ret = CbDebitServiceImpl.this.tradeService.fire(tx);
							} else {
								CbDebitServiceImpl.this.tradeService.rollback(tx);
								ret = new HashMap();
								((Map) ret).put("ret_code", "S");
							}
							success = "S".equals(((Map) ret).get("ret_code"));
						}
						if (success) {
							debit.setActualAmount(actualAmount);
							debit.setSettleDate(settleDate);

							debitState = "1";
							debit.setDebitState(debitState);
							debit.setRemark(remark);
							CbDebitServiceImpl.this.updateNotNull(debit);
							debits.add(debit);
							stats.addPassedRecord("1");
						}
					}
				}, new int[0]);
				try {
					if ("batch".equals(ChainBillUtil.getExpSettleMode(grpId))) {
						this.cbCreditService.creditByDebitId(debitId);
					}
				} catch (Exception e) {
					e.printStackTrace();
					this.logger.error("Credit error.", e);
				}
			} catch (Exception e) {
				e.printStackTrace();
				this.logger.error(getClass() + "��������", e);
				stats.addAbnormalRecord("2");
				stats.addAbnormalMsg(e.getMessage());
			}
		}
		String txSnHost = resQuota(debits);
		if (txSnHost != null) {
			stats.setTxSnHost(txSnHost);
		}
		return stats;
	}

	public List<CbDebit> selectOverdueDebit(String theDayBefore) {
		return this.cbDebitDao.selectOverdueDebit(theDayBefore);
	}

	@Pagination
	public List<PaymentStatsVo> queryDebitStatsList(PageLimit limit, PaymentStatsQueryVo paymentStatsQueryVo) {
		paymentStatsQueryVo.setCusName(StringUtil.getParameterLike(paymentStatsQueryVo.getCusName()));

		return this.cbDebitDao.queryDebitStatsList(paymentStatsQueryVo);
	}

	public Map<String, BigDecimal> sumDebitStatsList(PaymentStatsQueryVo paymentStatsQueryVo) {
		PageLimit limit = new PageLimit();
		limit.setDoPage(false);
		List<PaymentStatsVo> debitStatsList = queryDebitStatsList(limit, paymentStatsQueryVo);
		BigDecimal totAmt = BigDecimal.ZERO;
		BigDecimal totIns = BigDecimal.ZERO;
		BigDecimal totActlAmt = BigDecimal.ZERO;
		for (PaymentStatsVo debitStats : debitStatsList) {
			totAmt = totAmt.add(debitStats.getCusAmt());
			totIns = totIns.add(debitStats.getCusIns());
			totActlAmt = totActlAmt.add(debitStats.getCusActlAmt());
		}
		Object ret = new HashMap();
		((Map) ret).put("totAmt", totAmt);
		((Map) ret).put("totIns", totIns);
		((Map) ret).put("totActlAmt", totActlAmt);
		return (Map<String, BigDecimal>) ret;
	}

	@Pagination
	public List<CbDebitVo> selectDebitCashList(PageLimit limit, CbDebitQueryVo cbDebitQueryVo) {
		String cusName = cbDebitQueryVo.getCusName();
		if (!StringUtil.emptyAndNull(cusName)) {
			cusName = StringUtil.getParameterLike(cusName);
			cbDebitQueryVo.setCusName(cusName);
		}
		return this.cbDebitDao.selectDebitCashList(cbDebitQueryVo);
	}

	public Map<String, String> getCashMap(String debitId) {
		Map<String, String> cashMap = new HashMap();
		CbDebit debit = (CbDebit) selectByKey(debitId);
		cashMap.put(debit.getCusId(), debit.getCusName());

		String focalCoId = this.billExpHldrService.getFocalCoIdByBillId(debit.getBillId());
		String focalCoName = this.billExpHldrService.getFocalCoNameByBillId(debit.getBillId());
		cashMap.put(focalCoId, focalCoName);
		return cashMap;
	}

	public List<CbDebit> selectDebitBill(String workDate, String grpId, String... debitStates) {
		List<String> debitStateList = new ArrayList();
		for (String debitState : debitStates) {
			debitStateList.add(debitState);
		}
		return this.cbDebitDao.selectDebitBill(workDate, grpId, debitStateList);
	}

	public int updateSecurityBankAcct(String acctNo, String acctName, String cusId, String oldAcctNo) {
		return this.cbDebitDao.updateSecurityBankAcct(acctNo, acctName, cusId, oldAcctNo);
	}

	public CbDebit saveBillDebit(CbRec bill, String expDate, boolean delay) {
		CbDebit debit = null;
		String billState = bill.getBillState();
		if ((!"S005".equals(billState)) && (!"S009".equals(billState)) && (!"S017".equals(billState))
				&& (!"S012".equals(billState)) && (!"S011".equals(billState))) {
			return null;
		}
		debit = saveCbDebit(bill, expDate, delay);
		return debit;
	}

	private CbDebit saveCbDebit(CbRec bill, String debitDate, boolean delay) {
		CbHldr hldr = null;
		String rootId = bill.getRootId();
		String prntId = bill.getPrntId();
		if (StringUtil.emptyAndNull(prntId)) {
			rootId = bill.getBillId();
		}
		hldr = this.billExpHldrService.getHldr(rootId, 0);
		String hldrId = hldr.getHldrId();

		AcctBas acct = null;
		String debitType = "0";
		try {
			if (!delay) {
				acct = this.billExpHldrService.getDfltSettlAcct(hldrId);
				if (acct == null) {
					this.logger.error("��������[" + hldr.getHldrNm() + "]����������������.");
				}
				CbSnd snd = new CbSnd();
				snd.setBillId(rootId);
				CbSnd data = (CbSnd) this.cbSndService.selectOne(snd);
				if (data != null) {
					snd.setSndId(data.getSndId());
					snd.setSndState("1");
					this.cbSndService.updateNotNull(snd);
				}
			} else {
				CbDebit tmp = new CbDebit();
				tmp.setBillId(rootId);
				return (CbDebit) selectOne(tmp);
			}
		} catch (Exception e) {
			this.logger.error("����������������.", e);
		}
		return saveCbDebit(bill, debitDate, hldr, acct, debitType);
	}

	public CbDebit saveCbDebit(CbRec bill, String debitDate, CbHldr hldr, AcctBas acct, String debitType) {
		CbDebit debit = new CbDebit();
		String billId = bill.getBillId();
		debit.setDebitId(SystemUtil.getUUID());
		debit.setDebitType(debitType);
		debit.setBillId(billId);
		debit.setBillAmount(bill.getBillAmt());
		debit.setCusId(hldr.getHldrId());
		debit.setCusName(hldr.getHldrNm());
		if (acct != null) {
			debit.setAcctNo(acct.getAcctNo());
			debit.setAcctName(acct.getAcctNm());
			debit.setBankName(acct.getFiNm());
		}
		debit.setDebitState("0");
		debit.setAutomatic("0");
		debit.setDebitDate(debitDate);
		debit.setEditorId(CommonDataUtil.getUserId());
		debit.setEditTime(DateUtil.getSystemDateTime());
		save(debit);
		return debit;
	}

	public CbDebit selectAndLockByKey(String key) {
		return this.cbDebitDao.selectAndLockByKey(key);
	}

	public List<String> pmt(CbDebit debit, String txAbs) {
		List<String> abnormalMsgs = new ArrayList();
		List<CbDebitDtl> debitDtls = this.cbDebitDtlService.selectByDebitId(debit.getDebitId());
		String txSn = SystemUtil.getUUID();
		List<AcctTxRec> list = new ArrayList();
		String grpId = getGrpIdByDebitId(debit.getDebitId());
		for (CbDebitDtl debitDtl : debitDtls) {
			if ((!"batch".equals(ChainBillUtil.getExpSettleMode(grpId))) ||

					(!debit.getAcctNo().equals(debitDtl.getAcctNo()))) {
				if ((ChainBillUtil.onlinePay()) && (VirtualAcctUtil.onVirtual()) && (!enoughBalance(debit, null))) {
					String msg = "����[" + debit.getAcctNo() + "]��������";
					this.logger.warn(msg);
					abnormalMsgs.add(msg);
				} else {
					AcctTxRec tran = getAcctTxRec(debit, debitDtl, txSn, null);
					tran.setTxAbs(txAbs);
					list.add(tran);
				}
			}
		}
		if (list.size() == 0) {
			return abnormalMsgs;
		}
		Object result = null;
		if (ChainBillUtil.onlinePay()) {
			result = this.tradeService.fire(txSn, list);
		} else {
			this.tradeService.rollback(list);
			result = new HashMap();
			((Map) result).put("ret_code", "F");
		}
		boolean flag = "S".equals(((Map) result).get("ret_code"));
		String msg = "������������";
		for (AcctTxRec tran : list) {
			String txSts;
			if (flag) {
				txSts = "S";
				tran.setTxSnHost((String) ((Map) result).get("tx_sn"));
			} else {
				txSts = "F";
				abnormalMsgs.add(msg);
			}
			tran.setTxSts(txSts);
			this.AcctTxRecService.updateNotNull(tran);
		}
		return abnormalMsgs;
	}

	public String resQuota(List<CbDebit> debits) {
		if ((debits == null) || (debits.size() == 0)) {
			return null;
		}
		List<AcctTxRec> AcctTxRecs = new ArrayList();
		for (CbDebit debit : debits) {
			AcctTxRec txRec = findExistAcctTxRec(debit.getDebitId());
			if (txRec == null) {
				txRec = getResQuotaAcctTxRec(debit);
				AcctTxRecs.add(txRec);
			}
		}
		if (AcctTxRecs.size() == 0) {
			return null;
		}
		Object context = new CommandContext();

		((CommandContext) context).setValue("acctTxRecs", AcctTxRecs);
		ChainBase<AcctTxRec> chainBase = new ChainBase();
		chainBase.add(this.billExpDebitCreditTranCmd);
		chainBase.add(this.billAssetTranCmd);
		chainBase.execute((CommandContext) context);
		if (ChainBillUtil.onChain()) {
			Object txSnHost = ((CommandContext) context).getValue("txSnHost");
			if (txSnHost != null) {
				return (String) txSnHost;
			}
		}
		return null;
	}

	private AcctTxRec findExistAcctTxRec(String debitId) {
		AcctTxRec txRec = new AcctTxRec();
		txRec.setBizId(debitId);
		txRec.setTxType("cb_res_xqt");
		txRec.setTxSts("S");
		txRec.setCurrCode(AssetCode.XQT.name());
		return (AcctTxRec) this.AcctTxRecService.selectOne(txRec);
	}

	public void sendExpDebitMessage(String expDate, String finId, List<CbDebit> debits) {
		if (debits.size() > 0) {
			ExpDebitKeyWord keyWord = getExpDebitKeyWord(expDate, debits);
			try {
				MessageSender.sendMessageByTmpl(SpringContextUtil.getProperty("system.code"), "MT03103", keyWord,
						finId);
			} catch (Exception e) {
				e.printStackTrace();
				throw new DebitException(e.getMessage(), e);
			}
		}
	}

	public void sendExpDebitFailedMessage(CbDebit debit) {
		String finId = getFinId(debit);
		ExpDebitFailedKeyWord keyWord = getExpDebitFailedKeyWord(debit);
		try {
			MessageSender.sendMessageByTmpl(SpringContextUtil.getProperty("system.code"), "MT03104", keyWord, finId);
		} catch (Exception e) {
			e.printStackTrace();
			throw new DebitException(e.getMessage(), e);
		}
	}

	public boolean enoughBalance(CbDebit debit, String grpId) {
		boolean flag = true;
		String acctNo = debit.getAcctNo();
		try {
			this.billAcctBlcService.getBankAcctBlc(acctNo);
		} catch (Exception e) {
			this.logger.error("��������������������");
			e.printStackTrace();
		}
		if (grpId == null) {
			CbRec bill = this.billExpHldrService.getBill(debit.getBillId());
			grpId = bill.getGrpId();
		}
		AcctInfo acctInfo = new AcctInfo();
		acctInfo.setAcctNo(acctNo);
		acctInfo.setAcctType("1");
		acctInfo.setCurrCode(AssetCode.CNY.name());
		acctInfo.setBkpPrdCode(grpId);
		AcctInfo bas = this.billAcctService.getAcctCardInfo(acctInfo);
		if (bas == null) {
			this.billAcctBlcService.initAcctBkp(acctNo, AssetCode.CNY.name(), grpId, null, BigDecimal.ZERO);
			flag = false;
		} else if (bas.getAvailableAmt().compareTo(debit.getBillAmount()) < 0) {
			flag = false;
		}
		return flag;
	}

	public String getGrpIdByDebitId(String debitId) {
		CbDebit debit = (CbDebit) selectByKey(debitId);
		CbRec bill = this.billExpHldrService.getBill(debit.getBillId());
		return bill.getGrpId();
	}

	private AcctTxRec getResQuotaAcctTxRec(CbDebit debit) {
		AcctTxRec txRec = getCommAcctTxRec();
		txRec.setTxSn(SystemUtil.getUUID());
		txRec.setBizId(debit.getDebitId());
		txRec.setTxAmt(debit.getBillAmount());
		txRec.setTxAbs("��������");
		txRec.setTxType("cb_res_xqt");
		txRec.setOptType("qt_res");
		txRec.setCurrCode(AssetCode.XQT.name());
		txRec.setTxChnCode("C");

		CbRec bill = this.billExpHldrService.getBill(debit.getBillId());
		String finId = bill.getFinId();
		AcctBas txAcct = this.billExpHldrService.getTransientQuotaAcct(finId);
		if (txAcct == null) {
			throw new DebitException("��������������������-��������������");
		}
		txRec.setTxAcctNo(txAcct.getAcctNo());
		txRec.setTxAcctNm(txAcct.getAcctNm());
		txRec.setTxBankNm(txAcct.getFiNm());
		AcctBkp txAcctBkp = this.billAcctBlcService.getAcctBkp(txRec.getTxAcctNo(), txRec.getCurrCode(), null, null);
		txRec.setTxBkpId(txAcctBkp.getBkpId());

		AcctBas cpAcct = this.billExpHldrService.getCreditQuotaAcct(debit.getCusId());
		if (cpAcct == null) {
			throw new DebitException("����[" + debit.getCusName() + "]��������������");
		}
		txRec.setCpAcctNo(cpAcct.getAcctNo());
		txRec.setCpAcctNm(cpAcct.getAcctNm());
		txRec.setCpBankNm(cpAcct.getFiNm());
		AcctBkp cpAcctBkp = this.billAcctBlcService.getCreditAcctBkpByCont(finId, debit.getCusId());
		txRec.setCpBkpId(cpAcctBkp.getBkpId());
		return txRec;
	}

	private AcctTxRec getAcctTxRec(CbDebit debit, CbDebitDtl debitDtl, String txSn, String cashId) {
		AcctTxRec txRec = getCommAcctTxRec();
		txRec.setTxSn(txSn);
		txRec.setBizId(debit.getDebitId());
		txRec.setTxAmt(debitDtl.getAmount());
		txRec.setTxType("cb_exp_dbt");
		txRec.setCurrCode(AssetCode.CNY.name());
		txRec.setOptType("qt_trd");

		String grpId = null;
		if ((ChainBillUtil.onlinePay()) && (VirtualAcctUtil.onVirtual())) {
			CbRec bill = this.billExpHldrService.getBill(debit.getBillId());
			grpId = bill.getGrpId();
		}
		AcctBas txAcct;
		if (cashId == null) {
			txAcct = this.billAcctService.getCard(debit.getAcctNo());
		} else {
			txAcct = this.billExpHldrService.getCashAcct(cashId);
		}
		if (txAcct != null) {
			txRec.setTxAcctNo(txAcct.getAcctNo());
			txRec.setTxAcctNm(txAcct.getAcctNm());
			txRec.setTxBankNm(txAcct.getFiNm());
			AcctBkp txAcctBkp = this.billAcctBlcService.getAcctBkp(txRec.getTxAcctNo(), txRec.getCurrCode(), grpId,
					null);
			txRec.setTxBkpId(txAcctBkp.getBkpId());
		}
		AcctBas cpAcct = this.billAcctService.getCard(debitDtl.getAcctNo());
		if (cpAcct != null) {
			txRec.setCpAcctNo(cpAcct.getAcctNo());
			txRec.setCpAcctNm(cpAcct.getAcctNm());
			txRec.setCpBankNm(cpAcct.getFiNm());
			AcctBkp cpAcctBkp = this.billAcctBlcService.getAcctBkp(txRec.getCpAcctNo(), txRec.getCurrCode(), grpId,
					null);
			txRec.setCpBkpId(cpAcctBkp.getBkpId());
		}
		return txRec;
	}

	private AcctTxRec getOverdueInsAcctTxRec(String cashId, CbDebit debit, BigDecimal overdueIns) {
		AcctTxRec txRec = getCommAcctTxRec();
		txRec.setTxSn(SystemUtil.getUUID());
		txRec.setBizId(debit.getDebitId());
		txRec.setTxAmt(overdueIns);
		txRec.setTxType("cb_dbt_ins");
		txRec.setCurrCode(AssetCode.CNY.name());
		txRec.setTxChnCode("B");
		txRec.setOptType("qt_trd");

		String grpId = null;
		if ((ChainBillUtil.onlinePay()) && (VirtualAcctUtil.onVirtual())) {
			CbRec bill = this.billExpHldrService.getBill(debit.getBillId());
			grpId = bill.getGrpId();
		}
		AcctBas txAcct = this.billExpHldrService.getCashAcct(cashId);
		if (txAcct != null) {
			txRec.setTxAcctNo(txAcct.getAcctNo());
			txRec.setTxAcctNm(txAcct.getAcctNm());
			txRec.setTxBankNm(txAcct.getFiNm());
			AcctBkp txAcctBkp = this.billAcctBlcService.getAcctBkp(txRec.getTxAcctNo(), txRec.getCurrCode(), grpId,
					null);
			txRec.setTxBkpId(txAcctBkp.getBkpId());
		}
		String finId = this.billExpHldrService.getFinId(debit.getBillId());
		AcctBas cpAcct = this.billExpHldrService.getCashAcct(finId);
		if (cpAcct != null) {
			txRec.setCpAcctNo(cpAcct.getAcctNo());
			txRec.setCpAcctNm(cpAcct.getAcctNm());
			txRec.setCpBankNm(cpAcct.getFiNm());
			AcctBkp cpAcctBkp = this.billAcctBlcService.getAcctBkp(txRec.getCpAcctNo(), txRec.getCurrCode(), grpId,
					null);
			txRec.setCpBkpId(cpAcctBkp.getBkpId());
		}
		return txRec;
	}

	private AcctTxRec getCommAcctTxRec() {
		AcctTxRec txRec = new AcctTxRec();
		txRec.setTxId(SystemUtil.getUUID());
		txRec.setTxDt(SysDateUtil.getSystemDate());
		txRec.setTxTs(SysDateUtil.getSystemDateTime());
		txRec.setTxSts("I");
		String sourceCode = SpringContextUtil.getProperty("system.code");
		txRec.setSrcCode(sourceCode);
		txRec.setDataScLvl("B");
		txRec.setTxCashFlag("N");
		txRec.setTxReqFiCls("1");
		txRec.setTxOperator("System");
		return txRec;
	}

	private ExpDebitKeyWord getExpDebitKeyWord(String expDate, List<CbDebit> debits) {
		ExpDebitKeyWord keyWord = new ExpDebitKeyWord();
		String number = String.valueOf(debits.size());

		keyWord.setExpDate(DateUtil.parseDate(expDate, "yyyyMMdd", "yyyy-MM-dd"));
		keyWord.setTotAmt(getAmount(debits));
		keyWord.setNumber(number);
		return keyWord;
	}

	private String getFinId(CbDebit cbDebit) {
		return this.billExpHldrService.getFinId(cbDebit.getBillId());
	}

	private String getAmount(List<CbDebit> debits) {
		BigDecimal totAmt = BigDecimal.ZERO;
		for (CbDebit debit : debits) {
			totAmt = totAmt.add(debit.getBillAmount());
		}
		return String.valueOf(totAmt);
	}

	private ExpDebitFailedKeyWord getExpDebitFailedKeyWord(CbDebit debit) {
		ExpDebitFailedKeyWord keyWord = new ExpDebitFailedKeyWord();
		keyWord.setExpDate(DateUtil.parseDate(debit.getDebitDate(), "yyyyMMdd", "yyyy-MM-dd"));
		keyWord.setBillAmt(String.valueOf(debit.getBillAmount()));
		keyWord.setCusName(debit.getCusName());
		return keyWord;
	}
}
